/**
 * 	write on 2005-10-26 23:58:46.
 */
package org.nanhill.xmlro.gsp;

import static org.nanhill.xmlro.gsp.GspConstants.BOOLEAN_FALSE_NODE;
import static org.nanhill.xmlro.gsp.GspConstants.BOOLEAN_TRUE_NODE;
import static org.nanhill.xmlro.gsp.GspConstants.GSP_END;
import static org.nanhill.xmlro.gsp.GspConstants.GSP_START;
import static org.nanhill.xmlro.gsp.GspConstants.NULL_END;
import static org.nanhill.xmlro.gsp.GspConstants.*;

import java.util.Date;

import org.nanhill.xmlro.AbstractXmlroOutput;
import org.nanhill.xmlro.Serializer;
import org.nanhill.xmlro.SerializerFactory;
import org.nanhill.xmlro.XmlroException;
import org.nanhill.xmlro.gsp.packet.GspPacket;

/**
 * @author alin
 * 
 */
public class GspOutput extends AbstractXmlroOutput {

	private SerializerFactory serializerFactory;

	public void setSerializerFactory(SerializerFactory serializerFactory) {
		this.serializerFactory = serializerFactory;
	}

	public GspOutput(GspPacket obj, StringBuilder builder) {
		super(obj, builder);
	}

	public GspOutput(GspPacket obj) {
		super(obj);
	}

	public GspOutput() {
		super();
	};

	private GspPacket getGspPacket() {
		return (GspPacket) this.getParsed();
	}

	public void construct() throws GspException {
		this.writeHeader();
		Object body = this.getGspPacket().getBody();
		if (null != body) {
			try {
				this.writeObject(body);
			} catch (XmlroException e) {
				throw new GspException(e);
			}
		}
		this.writeFooter();
	}

	public void writeFooter() {
		this.getGspPacket().appendEndTag(product);
		append(GSP_END);
	}

	public void writeHeader() {
		// product.append(XML_HEADER);
		product.append(GSP_START);
		this.getGspPacket().appendBeginTag(product);
	}

	/**
	 * Writes a double value to the stream. The double will be written with the
	 * following syntax:
	 * 
	 * <code><pre>
	 *                                                                                                     &lt;double&gt;value&lt;/double&gt;
	 * </pre></code>
	 * 
	 * @param value
	 *            the double value to write.
	 */
	public void writeDouble(double value) {
		print(DOUBLE_START);
		print(value);
		print(DOUBLE_END);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.nanhill.protocol.gsp.io.GspOutput#writeBytes(byte[])
	 */
	public void writeBytes(byte[] v) {
		this.print(BASE64_START);
		this.printBase64(v);
		this.print(BASE64_END);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.nanhill.protocol.gsp.io.GspOutput#writeNull()
	 */
	public void writeNull() {
		this.print(NULL_START);
		this.print(NULL_END);
	}

	/**
	 * Writes a boolean value to the stream. The boolean will be written with
	 * the following syntax:
	 * 
	 * <code><pre>
	 *                                                                                                     &lt;boolean&gt;0&lt;/boolean&gt;
	 *                                                                                                     &lt;boolean&gt;1&lt;/boolean&gt;
	 * </pre></code>
	 * 
	 * @param value
	 *            the boolean value to write.
	 */
	public void writeBoolean(boolean value) {
		if (value)
			this.print(BOOLEAN_TRUE_NODE);
		else
			this.print(BOOLEAN_FALSE_NODE);
	}

	// /*
	// * (non-Javadoc)
	// *
	// * @see
	// org.nanhill.protocol.gsp.io.GspOutput#writeStruct(org.nanhill.protocol.gsp.type.data.StructGspData)
	// */
	// public void writeValueOf(StructGspData data) throws IOException {
	// this.print(data.getStartTag());
	// List<StructMemberGspData> members = data.getValue();
	// if (null == members) {
	// this.writeNull();
	// } else {
	// for (StructMemberGspData item : members) {
	// this.writeGspData(item);
	// }
	// }
	// this.print(data.getEndTag());
	// }

	/**
	 * Writes the list header to the stream. List writers will call
	 * <code>writeListBegin</code> followed by the list contents and then call
	 * <code>writeListEnd</code>.
	 * 
	 * <code><pre>
	 *                                                                                             &lt;array&gt;
	 *                                                                                             	&lt;data&gt;
	 *                                                                                             		&lt;int&gt;11&lt;/int&gt;
	 *                                                                                             		&lt;string&gt;alin&lt;/string&gt;
	 *                                                                                             	&lt;/data&gt;
	 *                                                                                             &lt;/array&gt;
	 * </pre></code>
	 */
	public void writeListBegin() {
		print(ARRAY_START);
	}

	public void writeListSize(int size) {
	}

	/**
	 * Writes the tail of the list to the stream.
	 */
	public void writeListEnd() {
		print(ARRAY_END);
	}

	/**
	 * Writes a string value to the stream using UTF-8 encoding. The string will
	 * be written with the following syntax:
	 * 
	 * <code><pre>
	 *                                                                                                   &lt;string&gt;string-value&lt;/string&gt;
	 * </pre></code>
	 * 
	 * If the value is null, nothing will be written.
	 * 
	 * @param v
	 *            the string value to write.
	 */
	public void writeString(String v) {
		print(STRING_START);
		this.printBase64(v);
		print(STRING_END);
	}

	/**
	 * Writes an integer value to the stream. The integer will be written with
	 * the following syntax:
	 * 
	 * <code><pre>
	 *                                                                                            &lt;int&gt;int value&lt;/int&gt;
	 * </pre></code>
	 * 
	 * @param value
	 *            the integer value to write.
	 */
	public void writeInt(int value) {
		print(INT_START);
		print(value);
		print(INT_END);
	}

	/**
	 * Writes a long value to the stream. The long will be written with the
	 * following syntax:
	 * 
	 * <code><pre>
	 *                                                                                           &lt;uint&gt;int value&lt;/uint&gt;
	 * </pre></code>
	 * 
	 * @param value
	 *            the long value to write.
	 */
	public void writeLong(long value) {
		print(UINT_START);
		print(value);
		print(UINT_END);
	}

	/**
	 * Writes the map header to the stream. Map writers will call
	 * <code>writeMapBegin</code> followed by the map contents and then call
	 * <code>writeMapEnd</code>. For example:
	 * 
	 * <code><pre>
	 *                                                                                          &lt;struct&gt;
	 *                                                                                          		&lt;member name=&quot;name&quot;&gt;
	 *                                                                                          			&lt;string&gt;alin&lt;/string&gt;
	 *                                                                                          		&lt;/member&gt;
	 *                                                                                          		&lt;member name=&quot;age&quot;&gt;
	 *                                                                                          			&lt;int&gt;23&lt;/int&gt;
	 *                                                                                          		&lt;/member&gt;
	 *                                                                                          &lt;/struct&gt;
	 * </pre></code>
	 * 
	 */
	public void writeMapBegin() {
		print(STRUCT_START);
	}

	/**
	 * Writes the tail of the map to the stream.
	 */
	public void writeMapEnd() {
		print(STRUCT_END);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.nanhill.protocol.gsp.io.GspOutput#writeMapMemberStart(java.lang.String)
	 */
	public void writeMapMemberBegin(String key) {
		this.print("<member name=\"");
		this.print(key);
		this.print("\">");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.nanhill.protocol.gsp.io.GspOutput#writeMapMemberEnd()
	 */
	public void writeMapMemberEnd(String key) {
		this.print("</member>");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.nanhill.protocol.xmlro.Output#writeByte(byte)
	 */
	public void writeChar(char value) {
		this.writeString(String.valueOf(value));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.nanhill.protocol.xmlro.Output#writeDate(java.util.Date)
	 */
	public void writeDate(Date date) {
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.nanhill.protocol.xmlro.Output#writeShort(short)
	 */
	public void writeShort(short value) {
		this.writeInt(value);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.nanhill.protocol.xmlro.Output#writeByte(byte)
	 */
	public void writeByte(byte value) {
		this.writeInt(value);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.nanhill.protocol.xmlro.Output#writeFloat(float)
	 */
	public void writeFloat(float v) {
		this.writeDouble(v);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.nanhill.xmlro.XmlroOutput#writeMapKey()
	 */
	public void writeMapKey(String key) {
		// TODO Auto-generated method stub

	}

	public void writeMapElementSplit() {
		// TODO Auto-generated method stub

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.nanhill.xmlro.XmlroOutput#writeListElementSplit()
	 */
	public void writeListElementSplit() {
		// TODO Auto-generated method stub

	}

	@Override
	protected Serializer getSerializer(Class clz) {
		return this.serializerFactory.getSerializer(clz);
	}

}
